// Copyright (C) 2009  Yann de ThÃ©
// 
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.


#ifndef TIME_H
#define TIME_H

/*!
 * \file time.h
 * \brief Class to manage time in real-time programs. Can handle astronomic times such as JD.
 * \author Yann de The
 * \version 1.0
 */

#include <sys/time.h>
#include <time.h>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <ostream>

#include <SpiceUsr.h>

#include <misc.h>

struct se_date
{
    int years; 		/*!< Years. All values are valid */
    int months;		/*!< Months. Valid values : 1 (January) - 12 (December) */
    int days; 		/*!< Days. Valid values 1 - 28,29,30,31 Depends on month.*/
    int hours; 		/*!< Hours. Valid values 0 - 23. */
    int minutes; 	/*!< Minutes. Valid values 0 - 59. */
    double seconds;	/*!< Seconds. Valid values 0 - 59.99999.... */
};

/*! \class Time
 * \brief class which represents a timer.
 *
 *  This class handles time : time intervals and absolute date. The latter can be expressed as a JD, or in seconds.
 */
class Time {
protected:
	double a_prevRealTime;
public:
	/*!
     *  \brief Current date in terms of Julian day (in seconds)
     *
	 *  See http://en.wikipedia.org/wiki/Julian_day for further information
	 *  
     */
	double JD;
	/*!
     *  \brief Time increment in seconds
	 *  
	 *  It is updated for each call of the update method. Its value depends on the speed of the processor.
	 *  You can use it in your real-time application to update the physics.
	 *  It is multiplied by TimeWrap to introduce time acceleration if necessary
     *
     */
	double dt;
	/*!
     *  \brief Current time in seconds
	 *  
	 *  It is updated for each call of the update method. Its value is the real physic time of your application
     *
     */
	double t;
	/*!
     *  \brief Time acceleration
     *
	 *  This parameter controls time acceleration. It must be set to 1 in order to have the time flowing at the same speed than in the actual world.
	 *  Set to 1 by default.
	 *  
     */double TimeWrap;
	
	/*!
     *  \brief Constructor
     */
	Time();
	/*!
     *  \brief Destructor
     *
     */
	~Time();
	
	/*!
     *  \brief Gets current date info from internal JD.
     *
     *  This methods returns a se_date structure, computed from the current date of the class.
     *
     *  \return A se_date structure
     */
	se_date getLNDate() const;
	
	/*!
     *  \brief Gets current date info from internal JD.
     *
     *  This methods returns a double, the TDB, computed from the current date of the class.
	 *	The value returned is readable by CSPICE (http://naif.jpl.nasa.gov/naif/).
	 *  See here for the definition of TDB http://en.wikipedia.org/wiki/Barycentric_Dynamical_Time
     *
     *  \return The TDB (double)
     */
	double getSpiceTDB() const;
	
	/*!
     *  \brief Increments the time by dt, taking time wrap into account.
     *
     *  \return The time increment
     */
	double update();
	
	/*!
     *  \brief Delays the program by the time given in argument
	 *
	 *  The program is completely frozen during a time given by the argument.
     *
     *  \param The delay in seconds
     */
	void wait(double delay);
};

double JDtoSpiceTDB(double JD);

// The JD is computed with this definition : http://en.wikipedia.org/wiki/Julian_day
double get_julian_from_sys();

void get_date_from_sys (struct se_date* date);

double get_julian_day (struct se_date* date);

std::string get_julian_day_str();

void get_date(double JD, struct se_date * date);

#endif
